//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#ifndef __USB_SYNC_H__
#define __USB_SYNC_H__

#include <ddk.h>
#include "nu_api.h"
#include "drvassistant.h"

//#define UsbRBuf_DEBUG
#ifdef UsbRBuf_DEBUG
#define DBGB(x...) kprintf(x)
#else
#define DBGB(x...)
#endif

#define MAXSIZE 64 * 1024

typedef struct _UsbRBuf_ {
    UInt8    data[MAXSIZE];
    UInt32   maxsize;
    UInt32   elemtype;
    UInt32   availsize;
    UInt32   elemidx;
    //DzMutex  lock;
}UsbRBuf, *PUsbRBuf;

static inline int UsbRBuf_Init(PUsbRBuf pbuf, int datatype)
{
    pbuf->maxsize = MAXSIZE;
    pbuf->elemtype = datatype;
    pbuf->availsize = pbuf->maxsize;
    pbuf->elemidx = 0;
    memset(pbuf->data, 0, pbuf->maxsize);

    return NOERROR;
}

static inline void UsbRBuf_UnInit(PUsbRBuf pbuf)
{
    pbuf->maxsize = 0;
    pbuf->elemtype = 0;
    pbuf->availsize = 0;
    pbuf->elemidx = 0;
    memset(pbuf->data, 0, pbuf->maxsize);
}

static inline void UsbRBuf_Reset(PUsbRBuf pbuf)
{
    pbuf->availsize = pbuf->maxsize;
    pbuf->elemidx = 0;
    memset(pbuf->data, 0, pbuf->maxsize);
}

static inline int UsbRBuf_Enqueue(PUsbRBuf pbuf, UInt8 *pdata, UInt32 lenth)
{
    UInt32 fn, ln;
    //WaitResult wr;

    //pbuf->lock.Lock(&wr);
    fn = lenth;
    ln = 0;
    DBGB("UsbRBuf_Enqueue:lenth=%d,fn=%d,pbuf->availsize=%d\n",lenth,fn,pbuf->availsize);
    if (fn > pbuf->availsize) {
        fn = pbuf->availsize; //drop data
    }
    DBGB("fn=%d\n",fn);
    if (0 == fn) {
        //pbuf->lock.Unlock();
        kprintf("------------------------------------------The UsbRBuf Queue is full!\n");
        return 0;
    }

    if ((pbuf->elemidx + fn) > pbuf->maxsize) {
        ln = (pbuf->elemidx + fn) - pbuf->maxsize;
        fn -= ln;
    }
    memcpy(pbuf->data + pbuf->elemidx * pbuf->elemtype, \
        pdata, pbuf->elemtype * fn);
    pbuf->elemidx += fn;

    if (ln) {
        pdata += (pbuf->elemtype * fn);
        memcpy(pbuf->data, pdata, pbuf->elemtype * ln);
        pbuf->elemidx = ln;
        fn += ln;
    }
    pbuf->availsize -= fn;
    //pbuf->lock.Unlock();

    return fn;
}

static inline int UsbRBuf_Dequeue(PUsbRBuf pbuf, UInt8 *pdata, UInt32 lenth)
{
    UInt32 fn, ln, idx;
    //WaitResult wr;

    //pbuf->lock.Lock(&wr);
    fn = lenth;
    ln = 0;
    DBGB("UsbRBuf_Dequeue:fn=%d\n",fn);//DBGB("\n");
    if (fn > (pbuf->maxsize - pbuf->availsize)) {
        fn = (pbuf->maxsize - pbuf->availsize); //data not enough
    }
    DBGB("UsbRBuf_Dequeue:fn=%d,pbuf->maxsize=%d,pbuf->availsize=%d\n",fn,pbuf->maxsize,pbuf->availsize);
    if (0 == fn) {
        //pbuf->lock.Unlock();
        return 0;
    }

    idx = (pbuf->elemidx + pbuf->availsize) % pbuf->maxsize;
    if ((idx + fn) > pbuf->maxsize) {
        ln = (idx + fn) - pbuf->maxsize;
        fn -= ln;
    }
    memcpy(pdata, pbuf->data + idx * pbuf->elemtype, pbuf->elemtype * fn);
    if (ln) {
        pdata += (pbuf->elemtype * fn);
        memcpy(pdata, pbuf->data, pbuf->elemtype * ln);
        fn += ln;
    }
    pbuf->availsize += fn;
    //pbuf->lock.Unlock();

    return fn;
}

class CUsbsync : public CDeviceDriver {
public:
    CARAPI Read(
        /* [in] */ Int64 u64Offset,
        /* [in] */ Int32 bytesToRead,
        /* [out] */ MemoryBuf * pBuffer,
        /* [out] */ IEvent * * ppCompletionEvent);

    CARAPI Write(
        /* [in] */ Int64 offset,
        /* [in] */ const MemoryBuf &buffer,
        /* [out] */ Int32* pBytesWritten,
        /* [out] */ IEvent** completionEvent);

    CARAPI Control(
        /* [in] */ Handle32 controlCode,
        /* [in] */ const MemoryBuf &inBuffer,
        /* [out] */ MemoryBuf* pOutBuffer,
        /* [out] */ IEvent** completionEvent);

    virtual void Dispose() {}

    CUsbsync();
    ~CUsbsync();
    int Initialize(void);
    void UnInit();

    ECode Usbsync_Wake();
    void  Usbsync_Stop();

public :
    DzMutex      m_Lock;
    //DzCondition  m_SyncRd;
    DzEvent   m_event;
    UsbRBuf      m_buffer;

    UInt32       m_EventToPost;
    Boolean      m_IsSync, m_IsInit, m_IsPostEvent;//, m_bRead
    IEvent      *m_pRbufEvent;
};

#define UCDC_INIT           0x0000D001
#define UCDC_STOP           0x0000D002
#define UCDC_WAKE           0x0000D003
#define UCDC_SET_SYNC       0x0000D004
#define UCDC_SET_ASYNC      0x0000D005
#define UCDC_SET_PRIF       0x0000D006
#define UCDC_CLR_BUF        0x0000D007
#define UDCD_WAIT_EVENT     0xA000D001
#define UDCD_SET_EVENT      0xA000D002

#define UVCP_SIGNAL_OUT     0x08001FFF
#define UVCP_RX_CHAR        0x80001000
#define UVCP_ENQ_FAIL       0x80001002

#endif
